Skip to content

Premium Analytics: port the Locations stats widget#49513

Open
dognose24 wants to merge 11 commits into
update/pa-introduce-customize-dashboardfrom
add/wooa7s-1491-port-stats-module-locations
Open

Premium Analytics: port the Locations stats widget#49513
dognose24 wants to merge 11 commits into
update/pa-introduce-customize-dashboardfrom
add/wooa7s-1491-port-stats-module-locations

Conversation

@dognose24

@dognose24 dognose24 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #

Proposed changes

Ports the Locations module from Jetpack Stats (Calypso's client/my-sites/stats/features/modules/stats-locations) into the Premium Analytics customizable dashboard as a jpa/locations widget, on the dashboard introduced by #49502.

  • Widget (widgets/locations/): world map (@automattic/charts GeoChart) + a country leaderboard (widgets-toolkit LeaderboardChart: flags, share bars), presented like the visitors-by-location widget. Attributes: range (trailing-window presets, default last 30 days; date is omitted so the endpoint anchors "today" in the site's timezone) and max. Loading/empty states and a bundled sample-data fallback (marked "Sample data") when live data isn't available.
  • Data goes through the stats-admin proxy: GET /jetpack/v4/stats-app/sites/{blogId}/stats/country-views (summarized), normalized by a widget-local port of Calypso's statsCountryViews normalizer (country/summary branch).
  • Blog id bridge (src/stats-config.php): exposes the connected site's blog id to the dashboard page as window.configData.blog_id (the Odyssey convention) via an inline script on wp-api-fetch, hooked to both page-init actions. Stats widgets need the id because the proxy bakes it into the route. No-ops (→ sample data) when the site isn't connected.
  • Wires internal-package resolution for widget code via link:packages/* deps on the parent manifest, so widgets can consume @jetpack-premium-analytics/widgets-toolkit; widgets resolve imports against the parent manifest.

Deviations from upstream (documented in the widget README)

  • Country-level only for v1 — the Regions/Cities views and the country filter are follow-ups; stats-admin's dedicated …/stats/location-views/(country|region|city) route makes them reachable when we get there.
  • Calypso-only infrastructure is intentionally not ported: Redux state + QuerySiteStats, calypso-router, the gating/upsell flow, the Jetpack-version upgrade prompt, and analytics event tracking.
  • The map renders via the in-repo @automattic/charts GeoChart (react-google-charts) instead of Calypso's hand-rolled Google Charts loader; countries resolution needs no Maps API key.
  • Widget id is jpa/locations (host namespace).

Known limitations / follow-ups

  • The blog-id bridge is expected to be subsumed by the PA data package integration (feat(premium-analytics): port data package from next-woocommerce-analytics #49263 landed the package; stats widgets aren't on it yet).
  • Widget title/attribute labels in widget.json/widget.ts aren't translatable yet — pending an i18n convention for the widget contract (same situation as hello-world).
  • Regions/Cities + country filter, per above.

Related product discussion/links

Does this pull request change what data or activity we track or use?

No.

Testing instructions

Requires pnpm ^11.5 and Node ^24.15. After checkout, run pnpm install to reconcile the lockfile.

  • Build: pnpm --filter @automattic/jetpack-premium-analytics buildhello-world and locations widgets both build, and build/widgets/registry.php registers jpa/locations.
  • Typecheck: pnpm --filter @automattic/jetpack-premium-analytics typecheck — only the pre-existing useSelect/preferences errors in widget-dashboard/widget-primitives remain (present on the base branch; verified with the widget removed).
  • On a Jetpack-connected test site with the package synced:
    1. Open the Premium Analytics admin page → view source: window.configData.blog_id = <wpcom blog id>; is inlined before wp-api-fetch runs.
    2. Customize → Add widget → insert "Locations" (map-marker icon) → the world map and the flag leaderboard render side by side with live data and no "Sample data" badge.
    3. DevTools → Network: GET /wp-json/jetpack/v4/widget-modules lists jpa/locations; widgets/locations/render.min.js loads as a separate chunk on mount; one …/stats-app/sites/{id}/stats/country-views?period=day&…&summarize=1 request fires.
    4. On a disconnected site (or with the request blocked): the widget falls back to the bundled sample list with the "Sample data" badge instead of breaking.
截圖 2026-06-11 凌晨12 01 39

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports Jetpack Stats’ Locations module into Premium Analytics as a new jpa/locations dashboard widget, including UI (GeoChart + ranked list), a widget-local data hook/normalizer, and the server-side blog-id bridge needed to call the stats-admin proxy route.

Changes:

  • Add the jpa/locations widget (metadata/type definition, render UI, styles, README, and widget-local package manifest).
  • Add a useLocationViews hook that fetches /jetpack/v4/stats-app/sites/{blogId}/stats/country-views and normalizes the summarized response, with a sample-data fallback.
  • Expose the connected WordPress.com blog id on the dashboard page via window.configData.blog_id and wire required JS deps (@automattic/charts, @wordpress/api-fetch) + lockfile.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
projects/packages/premium-analytics/widgets/locations/widget.ts Declares the widget type, icon, presentation, and attributes (period/max).
projects/packages/premium-analytics/widgets/locations/widget.json Adds widget metadata for discovery/inserter (title/description/category).
projects/packages/premium-analytics/widgets/locations/use-location-views.ts Implements fetch + normalization + sample-data fallback for country views.
projects/packages/premium-analytics/widgets/locations/style.module.css Styles for widget layout, placeholder, list rows, and sample badge.
projects/packages/premium-analytics/widgets/locations/render.tsx Renders the GeoChart + ranked country list with loading/empty states.
projects/packages/premium-analytics/widgets/locations/README.md Documents scope, upstream deviations, and data/API dependencies.
projects/packages/premium-analytics/widgets/locations/package.json Declares widget-local dependencies (charts, api-fetch, ui, etc.).
projects/packages/premium-analytics/src/stats-config.php Adds inline config to expose window.configData.blog_id on the dashboard page.
projects/packages/premium-analytics/src/class-analytics.php Loads the new stats-config bridge during package init.
projects/packages/premium-analytics/package.json Adds @automattic/charts and @wordpress/api-fetch to package deps.
projects/packages/premium-analytics/changelog/add-locations-widget Adds a changelog entry for the new widget.
pnpm-lock.yaml Updates lockfile for the new/updated workspace dependencies.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment on lines +134 to +141
rows.push( {
// ’ in country names breaks the geo visualization, so normalize it.
label: view.location || info.country_full.replace( /’/g, "'" ),
countryCode: view.country_code,
countryFull: info.country_full,
value: view.views,
region: info.map_region ?? '',
} );
// is demoable. See README for the package support this needs.
if ( ! blogId ) {
setState( {
data: SAMPLE_LOCATIONS.slice( 0, max ),
return;
}
setState( {
data: SAMPLE_LOCATIONS.slice( 0, max ),
@nerrad nerrad force-pushed the update/pa-introduce-customize-dashboard branch from 91aa9fb to 909996e Compare June 11, 2026 22:51
@dognose24 dognose24 force-pushed the add/wooa7s-1491-port-stats-module-locations branch from ea86b35 to d4fdf61 Compare June 12, 2026 00:58
@jp-launch-control

jp-launch-control Bot commented Jun 12, 2026

Copy link
Copy Markdown

Code Coverage Summary

No summary data is available for parent commit 909996e, so cannot calculate coverage changes. 😴

If that commit is a feature branch rather than a trunk commit, this is expected. Otherwise, this should be updated once coverage for 909996e is available.

Full summary · PHP report

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment on lines +134 to +141
rows.push( {
// ’ in country names breaks the geo visualization, so normalize it.
label: view.location || info.country_full.replace( /’/g, "'" ),
countryCode: view.country_code,
countryFull: info.country_full,
value: view.views,
region: info.map_region ?? '',
} );
Comment on lines +176 to +184
if ( ! blogId ) {
setState( {
data: SAMPLE_LOCATIONS.slice( 0, max ),
isLoading: false,
isError: false,
isSample: true,
} );
return;
}
Comment on lines +212 to +222
.catch( () => {
if ( cancelled ) {
return;
}
setState( {
data: SAMPLE_LOCATIONS.slice( 0, max ),
isLoading: false,
isError: true,
isSample: true,
} );
} );
retrofox added 8 commits June 12, 2026 11:38
Private, source-consumed copy of @wordpress/grid until core publishes it.
Private, source-consumed copy of @wordpress/widget-primitives until core publishes it.
Private, source-consumed dashboard engine; depends on jetpack-widget-primitives and jetpack-grid.
Renders the WidgetDashboard engine via wp-build, bundling the grid/primitives/dashboard packages.
useWidgetTypes drives discovery via /wp/v2/widget-modules; hello-world builds as a lazy-loaded script module.
Hook the page boot-dependencies filter so widget modules reach the import map; move the endpoint to the jetpack/v4 namespace.
@wordpress/grid and widget-primitives references in widget-dashboard JSDoc/comments/README, per the faithful-source sync policy.
dognose24 and others added 3 commits June 12, 2026 11:58
Port the Jetpack Stats Locations module (country-level v1) from Calypso
into the Premium Analytics customizable dashboard as a jpa/locations
widget: GeoChart world map + ranked country list, fetching live data
through the stats-admin proxy. Expose the connected blog id to the
dashboard page (src/stats-config.php) so stats widgets can build their
proxy requests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the period attribute with date-range presets (today / 7 / 30 /
365 days) summarized server-side, and omit the date param so the window
anchors to today in the site's own timezone. period=day with num=1
showed only the current UTC day, which renders empty most mornings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the plain country list with the widgets-toolkit LeaderboardChart
(flags, share bars) beside the map, wrapped in GlobalChartsProvider since
LeaderboardChart does not self-provide the charts context the way
GeoChart does. Wire internal-package resolution for widget code via
link:packages/* deps on the parent manifest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dognose24 dognose24 force-pushed the add/wooa7s-1491-port-stats-module-locations branch from cae7f67 to 89d5fc8 Compare June 12, 2026 02:59
@nerrad nerrad force-pushed the update/pa-introduce-customize-dashboard branch from d060b2d to 5bb6dd9 Compare June 12, 2026 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants